/**
 * @author     ：PengMingJiu
 * @date       ：Created in 2022/3/15 9:20
 * @description：支持请求缓存
 */
import request from "@/utils/request";
import useState from "./useState";
import { type } from "./util";

const cache = new Map(),
    taskCache = Object.create(null)
let activeKey = null

function generateCacheKey(entity) {
    if (type(entity) === 'string') {
        return entity
    }
    if (type(entity) === 'object') {
        const {url, params = {}, dictKey} = entity
        const appendStr = new URLSearchParams();
        for (const k in params) {
            appendStr.append(k, params[k])
        }
        if (dictKey) {
            appendStr.append('dict', dictKey)
        }
        return url + "?" + appendStr
    }
    console.error('useRequest first params expects the String or Object ,but got ' + type(entity))
}

async function fetchData(entity) {
    const res = await request(entity)
    return Promise.resolve(res.data)
}

/**
 *
 * @param entity 请求体
 * @param memo 是否缓存
 */
function useRequest(entity, memo = false) {
    const cacheKey = generateCacheKey(entity)
    const [data, setData] = useState([]);
    const setDataAndCheck = () => {
        if (cache.has(cacheKey)) {
            setData(cache.get(cacheKey))
            activeKey = null
        }
        else
            fetchData(entity).then(data => {
                setData(data)
                cache.set(cacheKey, data)
                const tasks = taskCache[cacheKey]
                if (tasks) {
                    while (tasks.length) {
                        tasks.shift()()
                    }
                    taskCache[cacheKey] = null
                    delete taskCache[cacheKey]
                }
                activeKey = null
            })
    }
    if (memo) {
        if (activeKey === cacheKey) {
            const queue = taskCache[cacheKey] || []
            queue.push(() => {
                setData(cache.get(cacheKey))
            })
            taskCache[cacheKey] = queue
        }
        else {
            activeKey = cacheKey
            setDataAndCheck()
        }
    }
    else {
        fetchData(entity).then(setData)
    }
    return {
        data,
        refreshData() {
            cache.delete(cacheKey)
            setDataAndCheck()
        }
    }
}

export default useRequest
